home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 10 / amigaformatcd10.iso / -screenplay- / shareware / mris 1.1 / .mris1_1src.lha / draw.c < prev    next >
C/C++ Source or Header  |  1996-10-15  |  50KB  |  2,022 lines

  1. /* Copyright (C) 1993, 1992 Nathan Sidwell */
  2. /* RCS $Id: draw.c,v 4.17 1994/02/08 18:52:34 nathan Stable $ */
  3. #include "xmris.h"
  4. #ifndef AMIGAOS
  5. #include "time.h"
  6. #endif
  7. /*{{{  board load error masks*/
  8. #define ERROR_FILL              0x0001
  9. #define ERROR_BACKGROUND        0x0002
  10. #define ERROR_APPLES            0x0004
  11. #define ERROR_APPLE_POSITION    0x0008
  12. #define ERROR_PATH              0x0010
  13. #define ERROR_CHAR              0x0020
  14. #define ERROR_STRING            0x0040
  15. #define ERROR_INCONSISTANT      0x0080
  16. #define ERROR_NO_CHERRIES       0x0100
  17. #define ERROR_TOO_FEW_APPLES    0x0200
  18. #define ERROR_NO_DEN            0x0400
  19. #define ERROR_NO_PLAYER         0x0800
  20. #define ERROR_BAD_APPLES        0x1000
  21. #define ERROR_SYNTAX            0x2000
  22. #define ERROR_EOF               0x4000
  23. #define ERROR_READING           0x8000
  24. #define ERROR_MALLOC           0x10000
  25. #define ERROR_OPEN             0x20000
  26. #define ERROR_TOO_MANY         0x40000
  27. #define ERROR_FIX_MASK          0x0DFF
  28. #define ERROR_FATAL_MASK       0x7E000
  29. #define ERROR_KEEP_MASK        0x7C000
  30. /*}}}*/
  31. #ifndef AMIGAOS
  32. #define INCLUDE_LIMIT 16
  33. #define FILE_SUFFIX ".gdn"
  34. #define FILE_SUFFIX_LEN 4
  35. /*{{{  typedef struct Include*/
  36. typedef struct Include
  37. {
  38.   char CONST *name;   /* filename NULL for internal */
  39.   long      seek;     /* seek to next line */
  40.   unsigned  error;    /* error line */
  41.   unsigned  line;     /* line number */
  42.   unsigned  start;    /* start of garden line */
  43.   unsigned  garden;   /* garden number */
  44. } INCLUDE;
  45. /*}}}*/
  46. /*{{{  parse*/
  47. static struct
  48. {
  49.   INCLUDE   stack[INCLUDE_LIMIT]; /* include information */
  50.   unsigned  depth;    /* current include depth */
  51.   size_t    limit;    /* size of buffer */
  52.   char      *text;    /* line text */
  53. } parse;
  54. /*}}}*/
  55. /*{{{  static BOARD internal_boards[] =*/
  56. /*
  57.  * 0-9A-F selected apples on background.
  58.  * X      fully connected path w/o cherry
  59.  * x      fully connected path w cherry
  60.  * H-W    explicitly connected path w/o cherry
  61.  * h-w    explicitly connected path w cherry
  62.  * @      cherry on background
  63.  * +      background denying random apple
  64.  * .      background permitting random apple
  65.  */
  66. static BOARD internal_boards[] =
  67. {
  68. #include "digits.gdn"
  69. };
  70. /*}}}*/
  71. /*{{{  static char CONST *text_error[] =*/
  72. static char CONST *text_error[] =
  73. {
  74.   "Bad fill pattern",
  75.   "Bad background colour",
  76.   "Too many apples",
  77.   "Bad apple position",
  78.   "Required paths missing",
  79.   "Bad character",
  80.   "String wrong length",
  81.   "Inconistant paths",
  82.   "No cherries",
  83.   "Too few apple locations",
  84.   "No den",
  85.   "No player",
  86.   "Inconsistant apples",
  87.   "Syntax error",
  88.   "Unexpected EOF",
  89.   "Error reading file",
  90.   "Cannot malloc",
  91.   "Cannot open file",
  92.   "Too many includes",
  93. };
  94. /*}}}*/
  95. #else
  96. #include "Catalog.h"
  97. #endif /* !AMIGAOS */
  98. /*{{{  prototypes*/
  99. static VOIDFUNC draw_ball PROTOARG((unsigned));
  100. static VOIDFUNC plot_ball PROTOARG((unsigned, int, int));
  101. static VOIDFUNC new_board_draw PROTOARG((VOIDARG));
  102. #ifndef AMIGAOS
  103. static unsigned check_board PROTOARG((BOARD *));
  104. static VOIDFUNC read_boards PROTOARG((char CONST *, char CONST *));
  105. static unsigned read_line PROTOARG((FILE *, INCLUDE *));
  106. #endif /* !AMIGAOS */
  107. /*}}}*/
  108. /*{{{  void add_background(x, y, w, h)*/
  109. extern VOIDFUNC add_background
  110. FUNCARG((x, y, width, height),
  111.     int       x
  112. ARGSEP  int       y
  113. ARGSEP  unsigned  width
  114. ARGSEP  unsigned  height
  115. )
  116. /*
  117.  * adds an area to the background update list
  118.  */
  119. {
  120.   BACKGROUND *bptr;
  121.  
  122.   assert(update.back.backs != BACK_UPDATES);
  123.   bptr = &update.back.list[update.back.backs++];
  124.   bptr->place.x = x;
  125.   bptr->place.y = y;
  126.   bptr->size.x = width;
  127.   bptr->size.y = height;
  128.   return;
  129. }
  130. /*}}}*/
  131. /*{{{  ANIMATE animate_zoom(next)*/
  132. extern FUNCANIMATE(animate_zoom, next)
  133. /*
  134.  * zooms out on the initial board
  135.  * and then return from whence I came
  136.  */
  137. {
  138.   static PROTOANIMATE((*rts));
  139.   static unsigned demo;
  140.   PROTOVOID(*then);
  141.   
  142.   then = (PROTOVOID(*))animate_zoom;
  143.   if(next)
  144.     /*{{{  start*/
  145.     {
  146.       rts = (PROTOANIMATE((*)))next;
  147.       XFillRectangle(display.display, display.copy, GCN(GC_CLEAR),
  148.       BORDER_LEFT + 1, BORDER_TOP + 1, BOARD_WIDTH - 2, BOARD_HEIGHT - 2);
  149.       global.missed = 0;
  150.       refresh_window();
  151.       XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  152.       BORDER_LEFT + 1, BORDER_TOP + 1, BOARD_WIDTH - 2, BOARD_HEIGHT - 2,
  153.       BORDER_LEFT + 1, BORDER_TOP + 1);
  154.       /*{{{  do the apple sprites*/
  155.       {
  156.     int       i;
  157.     APPLE     *aptr;
  158.         
  159.     for(aptr = apple.list, i = apple.apples; i--; aptr++)
  160.       {
  161.         SPRITE    *sptr;
  162.         
  163.         sptr = &sprites[SPRITE_APPLE];
  164.         XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  165.         0, 0, CELL_WIDTH, CELL_HEIGHT, aptr->pixel.x, aptr->pixel.y);
  166.         XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  167.         0, 0, CELL_WIDTH, CELL_HEIGHT, aptr->pixel.x, aptr->pixel.y);
  168.       }
  169.       }
  170.       /*}}}*/
  171.       demo = global.state == MODE_DEMO;
  172.       timer_set(ZOOM_RATE, TIMING_PAUSE);
  173.       global.count = 0;
  174.       global.state = MODE_ZOOM;
  175.     }
  176.     /*}}}*/
  177.   if(global.count >= BOARD_HEIGHT / (2 * ZOOM_Y) || global.throw == 1 ||
  178.       (demo && (global.pause
  179. #ifndef AMIGAOS
  180.       || global.pressed & (1 << KEY_QUIT | 1 << KEY_KEYBOARD)
  181. #endif
  182.         )))
  183.     /*{{{  end*/
  184.     {
  185.       if(!demo && global.count < BOARD_HEIGHT / (2 * ZOOM_Y))
  186.     XCopyArea(display.display, display.copy, display.window,
  187.         GCN(GC_COPY), BORDER_LEFT + 1, BORDER_TOP + 1,
  188.         BOARD_WIDTH - 2, BOARD_HEIGHT - 2,
  189.         BORDER_LEFT + 1, BORDER_TOP + 1);
  190.       if(!demo && global.throw == 1)
  191.     global.throw = 2;
  192.       assert(rts != (PROTOANIMATE((*)))NULL);
  193.       then = (*rts)((PROTOVOID(*))NULL);
  194.     }
  195.     /*}}}*/
  196.   else
  197.     /*{{{  animate*/
  198.     {
  199.       unsigned  x, y;
  200.       
  201.       x = global.count * ZOOM_X;
  202.       y = global.count * ZOOM_Y;
  203.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  204.       CENTER_X - ZOOM_X - (int)x, CENTER_Y - ZOOM_Y - (int)y,
  205.       ZOOM_X, 2 * y + 2 * ZOOM_Y,
  206.       CENTER_X - ZOOM_X - (int)x, CENTER_Y - ZOOM_Y - (int)y);
  207.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  208.       CENTER_X + (int)x, CENTER_Y - ZOOM_Y - (int)y,
  209.       ZOOM_X, 2 * y + 2 * ZOOM_Y,
  210.       CENTER_X + (int)x, CENTER_Y - ZOOM_Y - (int)y);
  211.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  212.       CENTER_X - (int)x, CENTER_Y - ZOOM_Y - (int)y,
  213.       2 * x, ZOOM_Y,
  214.       CENTER_X - (int)x, CENTER_Y - ZOOM_Y - (int)y);
  215.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  216.       CENTER_X - (int)x, CENTER_Y + (int)y,
  217.       2 * x, ZOOM_Y,
  218.       CENTER_X - (int)x, CENTER_Y + (int)y);
  219.       global.count++;
  220.     }
  221.     /*}}}*/
  222.   return then;
  223. }
  224. /*}}}*/
  225. static VOIDFUNC draw_blank_background
  226. FUNCARG((map, cycle),
  227.     BOARD CONST *map
  228. ARGSEP  unsigned cycle
  229. )
  230. /*
  231.  * used to be part of blank_board()
  232.  */
  233. {
  234.   /*{{{  draw blank background*/
  235.   {
  236. #ifndef AMIGAOS
  237.     XGCValues gcv;
  238. #endif  /* AMIGAOS */
  239.     unsigned  back;
  240.  
  241.     XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  242.     0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
  243.     back = (map->colors + cycle) % BACKGROUNDS;
  244.     if(data.mono == False)
  245.       color_set((int)back);
  246.     /*{{{  draw blank board*/
  247.     {
  248. #ifndef AMIGAOS
  249.       gcv.fill_style = FillOpaqueStippled;
  250.       gcv.background = data.mono != False ? display.white :
  251.       colors[display.dynamic ? COLOR_DYNAMIC :
  252.       backgrounds[back][0]].pixel;
  253.       gcv.stipple = fills[map->fill].mask;
  254.       gcv.foreground = data.mono != False ?
  255.       display.black : colors[display.dynamic ?
  256.       COLOR_DYNAMIC + 1 : backgrounds[back][1]].pixel;
  257.       XChangeGC(display.display, GCN(GC_BOARD),
  258.       GCFillStyle | GCForeground | GCBackground | GCStipple, &gcv);
  259.       XFillRectangle(display.display, display.back, GCN(GC_BOARD),
  260.       BORDER_LEFT, BORDER_TOP, BOARD_WIDTH, BOARD_HEIGHT);
  261. #else
  262.       FillBack(map->fill,back,BORDER_LEFT,BORDER_TOP,BOARD_WIDTH,BOARD_HEIGHT);
  263. #endif  /* AMIGAOS */
  264.     }
  265.     /*}}}*/
  266.     XDrawLine(display.display, display.back, GCN(GC_BORDER),
  267.     BORDER_LEFT, BORDER_TOP, BORDER_LEFT + BOARD_WIDTH, BORDER_TOP);
  268.     XDrawLine(display.display, display.back, GCN(GC_BORDER),
  269.     BORDER_LEFT, BORDER_TOP + BOARD_HEIGHT - 1,
  270.     BORDER_LEFT + BOARD_WIDTH, BORDER_TOP + BOARD_HEIGHT - 1);
  271.     XDrawLine(display.display, display.back, GCN(GC_BORDER),
  272.     PIXELX(4, -1), PIXELY(-1, 0), PIXELX(4, -1), PIXELY(-1, CELL_HEIGHT));
  273.     XDrawLine(display.display, display.back, GCN(GC_BORDER),
  274.     PIXELX(4, XTRA_SPACING * 4 + CELL_WIDTH), PIXELY(-1, 0),
  275.     PIXELX(4, XTRA_SPACING * 4 + CELL_WIDTH), PIXELY(-1, CELL_HEIGHT));
  276.   }
  277.   /*}}}*/
  278.   /*{{{  add the xtra*/
  279.   {
  280.     unsigned  i;
  281.  
  282.     extra.escape = 0;
  283.     for(i = 5; i--;)
  284.       draw_extra_letter(i);
  285.   }
  286.   /*}}}*/
  287. }
  288. /*{{{  void blank_board(map, cycle)*/
  289. extern VOIDFUNC blank_board
  290. FUNCARG((map, cycle),
  291.     BOARD CONST *map
  292. ARGSEP  unsigned cycle
  293. )
  294. /*
  295.  * sets up a blank board
  296.  */
  297. {
  298.   memset(garden, 0, sizeof(garden));
  299.   draw_blank_background(map,cycle);
  300.   /*{{{  initialize stuff*/
  301.   {
  302.     update.back.backs = 0;
  303.     update.score.scores = 0;
  304.     player.old_ball.state = 0;
  305.     player.old_ball.count = 8;
  306.     player.ball.state = 0;
  307.     player.ball.count = 8;
  308.     monster.monsters = 0;
  309.     apple.apples = 0;
  310.   }
  311.   /*}}}*/
  312.   return;
  313. }
  314. /*}}}*/
  315. /*{{{  void bounding_box(x, y, width, height)*/
  316. extern VOIDFUNC bounding_box
  317. FUNCARG((x, y, width, height),
  318.     int       x
  319. ARGSEP  int       y
  320. ARGSEP  unsigned  width
  321. ARGSEP  unsigned  height
  322. )
  323. /*
  324.  * updates the update box so that it includes the
  325.  * supplied rectangle
  326.  * remember to empty the update box to the background list
  327.  */
  328. {
  329.   if(!update.set)
  330.     {
  331.       update.br.x = (update.tl.x = x) + width;
  332.       update.br.y = (update.tl.y = y) + height;
  333.       update.set = 1;
  334.     }
  335.   else
  336.     {
  337.       if(update.tl.x > x)
  338.     update.tl.x = x;
  339.       if(update.tl.y > y)
  340.     update.tl.y = y;
  341.       if(update.br.x < (int)(x + width))
  342.     update.br.x = (int)(x + width);
  343.       if(update.br.y < (int)(y + height))
  344.     update.br.y = (int)(y + height);
  345.     }
  346.   return;
  347. }
  348. /*}}}*/
  349. /*{{{  unsigned check_board(map)*/
  350. #ifndef AMIGAOS
  351. static
  352. #endif /* AMIGAOS */
  353. unsigned check_board
  354. FUNCARG((map),
  355.     BOARD     *map
  356. )
  357. /* checks a board is ok
  358.  * and fix if possible
  359.  * returns a mask of the errors
  360.  */
  361. {
  362.   unsigned  error;
  363.   
  364.   error = 0;
  365.   /*{{{  check characters*/
  366.   {
  367.     char      *cptr;
  368.     unsigned  ix;
  369.     
  370.     for(ix = CELLS_DOWN; ix--;)
  371.       for(cptr = map->map[ix]; *cptr; cptr++)
  372.     if(*cptr != GARDEN_RANDOM && *cptr != GARDEN_NOAPPLE &&
  373.         *cptr != GARDEN_CHERRY && !ISPATH(*cptr) && !ISAPPLE(*cptr))
  374.       {
  375.         error |= ERROR_CHAR;
  376.         *cptr = GARDEN_RANDOM;
  377.       }
  378.   }
  379.   /*}}}*/
  380.   /*{{{  check fill*/
  381.   if(map->fill >= FILLS)
  382.     {
  383.       error |= ERROR_FILL;
  384.       map->fill %= FILLS;
  385.     }
  386.   /*}}}*/
  387.   /*{{{  check background*/
  388.   if(map->colors >= BACKGROUNDS)
  389.     {
  390.       error |= ERROR_BACKGROUND;
  391.       map->colors %= BACKGROUNDS;
  392.     }
  393.   /*}}}*/
  394.   /*{{{  check apples number*/
  395.   if(map->apples > APPLE_LIMIT)
  396.     {
  397.       error |= ERROR_APPLES;
  398.       map->apples = APPLE_LIMIT;
  399.     }
  400.   /*}}}*/
  401.   /*{{{  check apple positioning*/
  402.   {
  403.     char      *cptr;
  404.     
  405.     for(cptr = map->map[CELLS_DOWN - 1]; *cptr; cptr++)
  406.       if(ISAPPLE(*cptr) || *cptr == GARDEN_RANDOM)
  407.     {
  408.       *cptr = GARDEN_NOAPPLE;
  409.       error |= ERROR_APPLE_POSITION;
  410.     }
  411.   }
  412.   /*}}}*/
  413.   /*{{{  check required paths*/
  414.   {
  415.     static CONST unsigned path[][2] =
  416.       {
  417.     {4, 0x2}, {5, 0x2}, {6, 0x2}, {7, 0x0},
  418.       };
  419.     unsigned  ix;
  420.     
  421.     for(ix = XtNumber(path); ix--;)
  422.       {
  423.     char      *cptr;
  424.     unsigned  c;
  425.     
  426.     cptr = (char *)(map->map) + path[ix][0];
  427.     c = *cptr;
  428.     if(!ISPATH(c))
  429.       {
  430.         error |= ERROR_PATH;
  431.         *cptr = GARDEN_PATH + path[ix][1];
  432.       }
  433.     else if((GARDENPATH(c) & path[ix][1]) != path[ix][1])
  434.       {
  435.         error |= ERROR_PATH;
  436.         *cptr = (GARDENPATH(c) | path[ix][1]) + GARDEN_PATH;
  437.       }
  438.       }
  439.   }
  440.   /*}}}*/
  441.   /*{{{  check integrity*/
  442.   {
  443.     unsigned  row;
  444.     char      *cptr;
  445.     
  446.     for(row = CELLS_DOWN; row--;)
  447.       for(cptr = map->map[row]; *cptr; cptr++)
  448.     /*{{{  check a cell*/
  449.     {
  450.       char      c;
  451.       
  452.       c = *cptr;
  453.       if(ISPATH(c))
  454.         {
  455.           unsigned  paths;
  456.           
  457.           paths = 0;
  458.           if(ISPATH(cptr[1]))
  459.         paths |= 2;
  460.           if(row != CELLS_DOWN - 1 &&
  461.           ISPATH(cptr[CELLS_ACROSS + 1]))
  462.         paths |= 1;
  463.           if((GARDENPATH(c) & paths) != (GARDENPATH(c) & 3))
  464.         {
  465.           error |= ERROR_INCONSISTANT;
  466.           *cptr = ((GARDENPATH(c) & 0xC) | paths) + GARDEN_PATH;
  467.         }
  468.         }
  469.     }
  470.     /*}}}*/
  471.   }
  472.   /*}}}*/
  473.   /*{{{  check totals*/
  474.   {
  475.     char      *cptr;
  476.     unsigned  count;
  477.     unsigned  totals[8];
  478.     
  479.     for(count = 8; count--;)
  480.       totals[count] = 0;
  481.     for(count = (CELLS_ACROSS + 1) * CELLS_DOWN,
  482.     cptr = (char *)map->map; count--; cptr++)
  483.       if(ISPATHCHERRY(*cptr) || *cptr == GARDEN_CHERRY)
  484.     totals[4]++;
  485.       else if(ISPATHDEN(*cptr))
  486.     totals[5]++;
  487.       else if(ISPATHPLAYER(*cptr))
  488.     totals[6]++;
  489.       else if(ISAPPLE(*cptr))
  490.     {
  491.       unsigned  value;
  492.       unsigned  ix;
  493.       
  494.       value = GARDENAPPLE(*cptr);
  495.       for(ix = 4; ix--; value >>= 1)
  496.         if(value & 1)
  497.           totals[ix]++;
  498.       totals[7]++;
  499.     }
  500.       else if(*cptr == GARDEN_RANDOM)
  501.     totals[7]++;
  502.     do
  503.       {
  504.     char    c;
  505.     
  506.     cptr = NULL;
  507.     c = 0;
  508.     if(!totals[5])
  509.       {
  510.         error |= ERROR_NO_DEN;
  511.         cptr = &map->map[DEFAULT_DEN_Y][DEFAULT_DEN_X];
  512.         c = GARDEN_PATH_DEN;
  513.       }
  514.     if(!totals[6])
  515.       {
  516.         error |= ERROR_NO_PLAYER;
  517.         cptr = &map->map[DEFAULT_PLAYER_Y][DEFAULT_PLAYER_X];
  518.         c = GARDEN_PATH_PLAYER;
  519.       }
  520.     if(!totals[4])
  521.       {
  522.         error |= ERROR_NO_CHERRIES;
  523.         cptr = &map->map[DEFAULT_CHERRY_Y][DEFAULT_CHERRY_X];
  524.         c = GARDEN_PATH_CHERRY;
  525.       }
  526.     if(cptr)
  527.       {
  528.         if(*cptr == GARDEN_CHERRY || ISPATHCHERRY(*cptr))
  529.           totals[4]--;
  530.         if(ISPATH(*cptr))
  531.           c = (GARDENPATH(*cptr) & 3) + c + GARDEN_PATH;
  532.         else if(c == GARDEN_PATH_CHERRY)
  533.           c = GARDEN_CHERRY;
  534.         else
  535.           c += GARDEN_PATH;
  536.         *cptr = c;
  537.       }
  538.     if(totals[7] < map->apples)
  539.       error |= ERROR_TOO_FEW_APPLES;
  540.       }
  541.     while(cptr);
  542.     for(count = 4; count--;)
  543.       if(totals[count] != map->apples)
  544.     error |= ERROR_BAD_APPLES;
  545.   }
  546.   /*}}}*/
  547. #ifdef AMIGAOS
  548.   error&=ERROR_KEEP_MASK;
  549. #endif /* AMIGAOS */
  550.   return error;
  551. }
  552. /*}}}*/
  553. #ifndef AMIGAOS
  554. /*{{{  void create_boards()*/
  555. extern VOIDFUNC create_boards FUNCARGVOID
  556. /* initializes the boards
  557.  * either from the internal ones, or
  558.  * by reading the user specified file
  559.  */
  560. {
  561.   read_boards(data.boards, NULL);
  562.   if(!board.boards)
  563.     {
  564.       fputs("No gardens found, using default\n", stderr);
  565.       parse.depth = 0;
  566.       read_boards(NULL, NULL);
  567.     }
  568.   if(parse.text)
  569.     free(parse.text);
  570.   return;
  571. }
  572. /*}}}*/
  573. #endif /* !AMIGAOS */
  574. /*{{{  void create_xtra_monster(ix)*/
  575. extern VOIDFUNC create_xtra_monster
  576. FUNCARG((ix),
  577.     unsigned  ix
  578. )
  579. /*
  580.  * create an xtra monster sprite, by taking the virgin one, and
  581.  * slapping a letter on its chest
  582.  */
  583. {
  584.   SPRITE    *dptr;
  585.   SPRITE    *sptr;
  586.   SPRITE    *lptr;
  587.   unsigned  i;
  588.  
  589.   sptr = &sprites[SPRITE_XTRA];
  590.   lptr = &sprites[SPRITE_EXTRA];
  591.   for(dptr = &sprites[SPRITE_XTRA], sptr = &sprites[SPRITE_XTRA_SOURCE],
  592.       i = MONSTER_IMAGES; i--; dptr++, sptr++)
  593.     {
  594.       XCopyArea(display.display, sptr->image, dptr->image, GCN(GC_COPY),
  595.       0, 0, CELL_WIDTH, CELL_HEIGHT, 0, 0);
  596.       XCopyArea(display.display, lptr->mask, dptr->image, GCN(GC_MASK),
  597.       (int)ix * (CELL_WIDTH / 2), 0, CELL_WIDTH / 2, CELL_HEIGHT / 2,
  598.       XTRA_LETTER_X, XTRA_LETTER_Y);
  599.       XCopyArea(display.display, lptr[!(extra.got & 1 << ix)].image,
  600.       dptr->image, GCN(GC_OR),
  601.       (int)ix * (CELL_WIDTH / 2), 0, CELL_WIDTH / 2, CELL_HEIGHT / 2,
  602.       XTRA_LETTER_X, XTRA_LETTER_Y);
  603.     }
  604.   return;
  605. }
  606. /*}}}*/
  607. /*{{{  void draw_ball(flag)*/
  608. static VOIDFUNC draw_ball
  609. FUNCARG((flag),
  610.     unsigned  flag
  611. )
  612. /*
  613.  * draws the old ball on or off the window
  614.  */
  615. {
  616.   switch(player.old_ball.state)
  617.   {
  618.     /*{{{  case 0:*/
  619.     case 0:
  620.     {
  621.       if(player.old_ball.count < 8)
  622.     {
  623.       COORD CONST *hold;
  624.  
  625.       hold = &ball_hold[player.old_ball.count * MONSTER_IMAGES +
  626.           player.old_ball.image];
  627.       plot_ball(flag, player.old_ball.pixel.x + hold->x,
  628.           player.old_ball.pixel.y + hold->y);
  629.     }
  630.       break;
  631.     }
  632.     /*}}}*/
  633.     /*{{{  case 1:*/
  634.     case 1:
  635.     {
  636.       plot_ball(flag, player.old_ball.pixel.x, player.old_ball.pixel.y);
  637.       break;
  638.     }
  639.     /*}}}*/
  640.     /*{{{  case 2: case 4:*/
  641.     case 2: case 4:
  642.     {
  643.       COORD     offset;
  644.       COORD     pixel;
  645.       unsigned  bits;
  646.  
  647.       pixel.x = player.old_ball.pixel.x;
  648.       pixel.y = player.old_ball.pixel.y;
  649.       if(player.old_ball.count)
  650.     {
  651.       offset.x = player.old_ball.count * BALL_EX;
  652.       offset.y = player.old_ball.count * BALL_EY;
  653.       bits = 0xFF;
  654.       /*{{{  set clips*/
  655.       {
  656.         if(pixel.x < offset.x)
  657.           bits &= 0xF8;
  658.         if(pixel.y < offset.y)
  659.           bits &= 0x3E;
  660.         if(pixel.x + offset.x > BOARD_WIDTH + BALL_WIDTH)
  661.           bits &= 0x8F;
  662.         if(pixel.y + offset.y > BOARD_HEIGHT + BALL_HEIGHT)
  663.           bits &= 0xE3;
  664.       }
  665.       /*}}}*/
  666.       /*{{{  do inner bits*/
  667.       {
  668.         if(bits & 0x01)
  669.           plot_ball(flag, pixel.x - offset.x, pixel.y - offset.y);
  670.         if(bits & 0x02)
  671.           plot_ball(flag, pixel.x - offset.x, pixel.y);
  672.         if(bits & 0x04)
  673.           plot_ball(flag, pixel.x - offset.x, pixel.y + offset.y);
  674.         if(bits & 0x08)
  675.           plot_ball(flag, pixel.x, pixel.y + offset.y);
  676.         if(bits & 0x10)
  677.           plot_ball(flag, pixel.x + offset.x, pixel.y + offset.y);
  678.         if(bits & 0x20)
  679.           plot_ball(flag, pixel.x + offset.x, pixel.y);
  680.         if(bits & 0x40)
  681.           plot_ball(flag, pixel.x + offset.x, pixel.y - offset.y);
  682.         if(bits & 0x80)
  683.           plot_ball(flag, pixel.x, pixel.y - offset.y);
  684.       }
  685.       /*}}}*/
  686.       offset.x *= 2;
  687.       offset.y *= 2;
  688.       /*{{{  set clips*/
  689.       {
  690.         if(pixel.x < offset.x)
  691.           bits &= 0xF8;
  692.         if(pixel.y < offset.y)
  693.           bits &= 0x3E;
  694.         if(pixel.x + offset.x > BOARD_WIDTH + BALL_WIDTH)
  695.           bits &= 0x8F;
  696.         if(pixel.y + offset.y > BOARD_HEIGHT + BALL_HEIGHT)
  697.           bits &= 0xE3;
  698.       }
  699.       /*}}}*/
  700.       /*{{{  do inner bits*/
  701.       {
  702.         if(bits & 0x01)
  703.           plot_ball(flag, pixel.x - offset.x, pixel.y - offset.y);
  704.         if(bits & 0x02)
  705.           plot_ball(flag, pixel.x - offset.x, pixel.y);
  706.         if(bits & 0x04)
  707.           plot_ball(flag, pixel.x - offset.x, pixel.y + offset.y);
  708.         if(bits & 0x08)
  709.           plot_ball(flag, pixel.x, pixel.y + offset.y);
  710.         if(bits & 0x10)
  711.           plot_ball(flag, pixel.x + offset.x, pixel.y + offset.y);
  712.         if(bits & 0x20)
  713.           plot_ball(flag, pixel.x + offset.x, pixel.y);
  714.         if(bits & 0x40)
  715.           plot_ball(flag, pixel.x + offset.x, pixel.y - offset.y);
  716.         if(bits & 0x80)
  717.           plot_ball(flag, pixel.x, pixel.y - offset.y);
  718.       }
  719.       /*}}}*/
  720.     }
  721.       else
  722.     plot_ball(flag, pixel.x, pixel.y);
  723.       break;
  724.     }
  725.     /*}}}*/
  726.     /*{{{  case 3:*/
  727.     case 3:
  728.       break;
  729.     /*}}}*/
  730.   }
  731.   return;
  732. }
  733. /*}}}*/
  734. /*{{{  void draw_extra()*/
  735. extern VOIDFUNC draw_extra FUNCARGVOID
  736. /*
  737.  * whack the current extra monster onto the background
  738.  */
  739. {
  740.   int x;
  741.  
  742.   x = PIXELX(4, extra.select * XTRA_SPACING);
  743.   back_sprite(SPRITE_XTRA + (chaotic() & 1), 1, x, PIXELY(-1, 0));
  744.   add_background(x, PIXELY(-1, 0), CELL_WIDTH, CELL_HEIGHT);
  745.   return;
  746. }
  747. /*}}}*/
  748. /*{{{  void draw_extra_letter(ix)*/
  749. extern VOIDFUNC draw_extra_letter
  750. FUNCARG((ix),
  751.     unsigned  ix
  752. )
  753. /*
  754.  * draw one of the extra letters on the background
  755.  * and add it to the update list
  756.  */
  757. {
  758.   SPRITE    *lptr;
  759.   int       x;
  760.  
  761.   lptr = &sprites[SPRITE_EXTRA];
  762.   x = PIXELX(4, ix * XTRA_SPACING);
  763.   XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  764.       x, PIXELY(-1, 0), CELL_WIDTH, CELL_HEIGHT);
  765.   if(display.background != COLOUR_ZERO)
  766.     XCopyArea(display.display, lptr->mask,
  767.     display.back, GCN(GC_MASK), (int)ix * (CELL_WIDTH / 2), 0,
  768.     CELL_WIDTH / 2, CELL_HEIGHT / 2,
  769.     x + XTRA_LETTER_X, PIXELY(-1, XTRA_LETTER_Y));
  770.   XCopyArea(display.display, lptr[!(extra.got & 1 << ix)].image,
  771.       display.back, GCN(GC_OR), (int)ix * (CELL_WIDTH / 2), 0,
  772.       CELL_WIDTH / 2, CELL_HEIGHT / 2,
  773.       x + XTRA_LETTER_X, PIXELY(-1, XTRA_LETTER_Y));
  774.   add_background(x, PIXELY(-1, 0), CELL_WIDTH, CELL_HEIGHT);
  775.   return;
  776. }
  777. /*}}}*/
  778. static VOIDFUNC new_board_draw FUNCARGVOID
  779. /*
  780.  * used to be part of new_board()
  781.  */
  782. {
  783.   XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  784.       BORDER_LEFT + (CELL_WIDTH + GAP_WIDTH) * 4 + GAP_WIDTH, BORDER_TOP + 1,
  785.       XTRA_SPACING * 4 + CELL_WIDTH, GAP_HEIGHT * 2 - 1);
  786.   draw_extra();
  787.   /*{{{  add the screen number*/
  788.   {
  789. #ifndef AMIGAOS
  790.     static char text[] = "Garden 000";
  791.     int       length;
  792.     
  793.     length = 7 + itoa(text + 7, (unsigned long)global.screen, 0);
  794.     XDrawImageString(display.display, display.back, GCN(GC_TEXT),
  795.     PIXELX(8, (int)font.width * 2),
  796.     PIXELY(-1, CELL_HEIGHT / 2 + font.center), text, length);
  797. #else
  798.     struct Rectangle Rectangle;
  799.     struct RastPort *RastPort;
  800.  
  801.     RastPort=display.back.Layer->rp;
  802.     Rectangle.MinX=PIXELX(8,0);
  803.     Rectangle.MaxX=PIXELX(CELLS_ACROSS,-GAP_WIDTH);
  804.     Rectangle.MinY=PIXELY(-1,CELL_HEIGHT/2-RastPort->TxHeight/2);
  805.     Rectangle.MaxY=Rectangle.MinY+RastPort->TxHeight;
  806.     if (InstallBounds(&display.back,Rectangle))
  807.       {
  808.     const char *Template;
  809.  
  810.     Template=GetString(MSG_GARDEN_NUMBER);
  811.     SetABPenDrMd(RastPort,display.black,display.black,JAM1);
  812.     Move(RastPort,Rectangle.MaxX-GS_StringWidth(Template,&global.screen,RastPort,Locale),
  813.          Rectangle.MinY+RastPort->TxBaseline);
  814.     GS_DrawString(Template,&global.screen,RastPort,Locale);
  815.     RemoveBounds(&display.back);
  816.       }
  817. #endif /* AMIGAOS */
  818.   }
  819.   /*}}}*/
  820.   add_score(0, 0, 0);
  821.   /*{{{  add lives*/
  822.   if(global.lives)
  823.     {
  824.       unsigned  lives;
  825.     
  826.       for(lives = global.lives - 1; lives--;)
  827.     back_sprite(SPRITE_PLAYER + 6, 0,
  828.         PIXELX((int)lives, 0), PIXELY(CELLS_DOWN, 0));
  829.     }
  830.   /*}}}*/
  831.   /*{{{  cut the background*/
  832.   {
  833.     unsigned  y, x;
  834.     COORD     cell;
  835.     CELL      *cptr;
  836.     
  837.     cptr = BOARDCELL(0, 0);
  838.     cell.x = PIXELX(0, 0);
  839.     cell.y = PIXELY(0, 0);
  840.     for(y = CELLS_DOWN; y--; cptr += CELL_STRIDE - CELLS_ACROSS,
  841.     cell.x -= (CELL_WIDTH + GAP_WIDTH) * CELLS_ACROSS,
  842.     cell.y += CELL_HEIGHT + GAP_HEIGHT)
  843.       for(x = CELLS_ACROSS; x--; cptr++, cell.x += CELL_WIDTH + GAP_WIDTH)
  844.     {
  845.       if(cptr->visit)
  846.         munch_hole(cptr, cell.x, cell.y);
  847.       if(cptr->sprite)
  848.         back_sprite(cptr->sprite, 1, cell.x, cell.y);
  849.       if(cptr->den)
  850.         XFillRectangle(display.display, display.back,
  851.         GCN(GC_CLEAR), cell.x - DEN_WIDTH,
  852.         cell.y - DEN_HEIGHT,
  853.         CELL_WIDTH + DEN_WIDTH * 2, CELL_HEIGHT + DEN_HEIGHT * 2);
  854.     }
  855.   }
  856.   /*}}}*/
  857.   XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  858.       0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  859. }
  860. /*{{{  void new_board()*/
  861. extern VOIDFUNC new_board FUNCARGVOID
  862. /*
  863.  * sets up a new board
  864.  */
  865. {
  866.   BOARD CONST *map;
  867.   int       spaces;
  868.  
  869. #ifndef AMIGAOS
  870.   map = board.list[(global.screen - 1) % board.boards];
  871. #else
  872.   map = &board.list[(global.screen - 1) % board.boards];
  873. #endif /* AMIGAOS */
  874.   blank_board(map, (global.screen - 1) / board.boards);
  875.   apple.apples = 0;
  876.   spaces = 0;
  877.   global.cherries = 0;
  878.   global.dens = 0;
  879.   /*{{{  copy the board*/
  880.   {
  881.     unsigned  mask;
  882.     
  883.     mask = 1 << (chaotic() % 4);
  884.     /*{{{  copy the text map*/
  885.     {
  886.       CELL      *cptr;
  887.       char CONST *mptr;
  888.       unsigned  y, x;
  889.       
  890.       mptr = (char CONST *)map->map;
  891.       for(y = 0, cptr = BOARDCELL(0, 0);
  892.       y != CELLS_DOWN; y++, cptr += CELL_STRIDE - CELLS_ACROSS, mptr++)
  893.     for(x = 0; x != CELLS_ACROSS; x++, mptr++, cptr++)
  894.       {
  895.         char    c;
  896.       
  897.         c = *mptr;
  898.         /*{{{  cherry?*/
  899.         if(c == GARDEN_CHERRY || ISPATHCHERRY(c))
  900.           {
  901.         cptr->sprite = SPRITE_CHERRY;
  902.         global.cherries++;
  903.           }
  904.         /*}}}*/
  905.         if(ISAPPLE(c))
  906.           /*{{{  explicit apple*/
  907.           {
  908.         cptr->xtra = data.random != False || !(mask & GARDENAPPLE(c));
  909.         if(!cptr->xtra && apple.apples < APPLE_LIMIT)
  910.           spawn_apple(x, y, 0, 0);
  911.           }
  912.           /*}}}*/
  913.         else if(ISPATH(c))
  914.           /*{{{  explicitly connected path*/
  915.           {
  916.         unsigned  bits;
  917.         
  918.         bits = GARDENPATH(c) & 3;
  919.         cptr->visit = 1;
  920.         if(bits & 1)
  921.           {
  922.             cptr[0].depths[1] = CELL_HEIGHT + GAP_HEIGHT;
  923.             cptr[CELL_STRIDE].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT);
  924.           }
  925.         if(bits & 2)
  926.           {
  927.             cptr[0].depths[3] = CELL_WIDTH + GAP_WIDTH;
  928.             cptr[1].depths[2] = -(CELL_WIDTH + GAP_WIDTH);
  929.           }
  930.         if(ISPATHDEN(c))
  931.           {
  932.             cptr->den = 1;
  933.             global.dens++;
  934.           }
  935.         else if(ISPATHPLAYER(c))
  936.           {
  937.             global.start.x = x;
  938.             global.start.y = y;
  939.           }
  940.           }
  941.           /*}}}*/
  942.         else if(c == GARDEN_RANDOM)
  943.           cptr->xtra = 1;
  944.         spaces += cptr->xtra;
  945.       }
  946.     }
  947.     /*}}}*/
  948.   }
  949.   /*}}}*/
  950.   if(apple.apples < map->apples)
  951.     /*{{{  add the apples*/
  952.     {
  953.       unsigned  count;
  954.  
  955.       for(count = map->apples - apple.apples; spaces && count--;)
  956.     {
  957.       CELL      *cptr;
  958.       
  959.       /*{{{  select a location*/
  960.       {
  961.         unsigned  count;
  962.  
  963.         do
  964.           count = chaotic();
  965.         while(count >= 256 / spaces * spaces);
  966.         count %= spaces;
  967. #ifndef AMIGAOS
  968.         for(cptr = BOARDCELL(0, 0); !cptr->xtra || !count--; cptr++)
  969.           /* EMPTY */;
  970. #else
  971.         for(cptr = BOARDCELL(0, 0); !cptr->xtra || count--; cptr++)
  972.           /* EMPTY */;
  973. #endif
  974.       }
  975.       /*}}}*/
  976.       cptr->apple = 1;
  977.       cptr->xtra = 0;
  978.       spaces--;
  979.       /*{{{  clear surround*/
  980.       {
  981.         static CONST int offsets[] = {-1, 1, CELL_STRIDE, -CELL_STRIDE};
  982.         unsigned ix;
  983.         
  984.         for(ix = sizeof(offsets) / sizeof(offsets[0]); ix--;)
  985.           {
  986.         CELL    *optr;
  987.         
  988.         optr = cptr + offsets[ix];
  989.         spaces -= (int)optr->xtra;
  990.         optr->ball |= optr->xtra;
  991.         optr->xtra = 0;
  992.           }
  993.       }
  994.       /*}}}*/
  995.       /*{{{  run out of spaces?*/
  996.       if(spaces <= 0 && count)
  997.         {
  998.           unsigned  count;
  999. #ifdef AMIGAOS
  1000.           CELL *cptr;
  1001. #endif
  1002.           
  1003.           for(count = CELLS_DOWN * CELL_STRIDE, cptr = BOARDCELL(0, 0);
  1004.           count--; cptr++)
  1005.         if(cptr->ball)
  1006.           {
  1007.             cptr->ball = 0;
  1008.             cptr->xtra = 1;
  1009.             spaces++;
  1010.           }
  1011.         }
  1012.       /*}}}*/
  1013.       spawn_apple((cptr - BOARDCELL(0, 0)) % CELL_STRIDE,
  1014.           (cptr - BOARDCELL(0, 0)) / CELL_STRIDE, 0, 0);
  1015.     }
  1016.     }
  1017.     /*}}}*/
  1018.   new_board_draw();
  1019. }
  1020. /*}}}*/
  1021. /*{{{  void plot_ball(flag, x, y)*/
  1022. static VOIDFUNC plot_ball
  1023. FUNCARG((flag, x, y),
  1024.     unsigned  flag
  1025. ARGSEP  int       x
  1026. ARGSEP  int       y
  1027. )
  1028. /*
  1029.  * plots the ball centered on the given coordinate
  1030.  * flag is 0 for unplot, 1 for plot
  1031.  */
  1032. {
  1033.   if(flag)
  1034.     {
  1035.       XCopyArea(display.display, sprites[SPRITE_BALL].mask, display.copy,
  1036.       GCN(GC_MASK), 0, 0, BALL_WIDTH, BALL_HEIGHT,
  1037.       x - BALL_WIDTH / 2, y - BALL_HEIGHT / 2);
  1038.       XCopyArea(display.display, sprites[SPRITE_BALL].image, display.copy,
  1039.       GCN(GC_OR), 0, 0, BALL_WIDTH, BALL_HEIGHT,
  1040.       x - BALL_WIDTH / 2, y - BALL_HEIGHT / 2);
  1041.     }
  1042.   add_background(x - BALL_WIDTH / 2, y - BALL_HEIGHT / 2,
  1043.       BALL_WIDTH, BALL_HEIGHT);
  1044.   return;
  1045. }
  1046. /*}}}*/
  1047. #ifndef AMIGAOS
  1048. /*{{{  void read_boards()*/
  1049. static VOIDFUNC read_boards
  1050. FUNCARG((name, parent),
  1051.     char CONST *name
  1052. ARGSEP  char CONST *parent
  1053. )
  1054. /* read a board file
  1055.  * recurses to deal with include
  1056.  */
  1057. {
  1058.   INCLUDE   *sptr;
  1059.   FILE      *stream;
  1060.   unsigned  error;
  1061.   BOARD   *bptr;
  1062.  
  1063.   sptr = &parse.stack[parse.depth];
  1064.   sptr->name = NULL;
  1065.   error = 0;
  1066.   sptr->line = 0;
  1067.   sptr->start = 0;
  1068.   sptr->garden = 0;
  1069.   stream = NULL;
  1070.   /*{{{  open?*/
  1071.   if(name)
  1072.     {
  1073.       char      *filename;
  1074.       size_t    length;
  1075.       
  1076.       length = strlen(name);
  1077.       if(*name == '/')
  1078.     {
  1079.       filename = XtMalloc(length + 1 + FILE_SUFFIX_LEN);
  1080.       strcpy(filename, name);
  1081.       strcpy(&filename[length], FILE_SUFFIX);
  1082.       if(filename)
  1083.         {
  1084.           stream = fopen(filename, "r");
  1085.           if(!stream)
  1086.         {
  1087.           filename[length] = 0;
  1088.           stream = fopen(filename, "r");
  1089.         }
  1090.         }
  1091.       else
  1092.         error = ERROR_MALLOC;
  1093.     }
  1094.       else
  1095.     {
  1096.       size_t    offset;
  1097.       
  1098.       filename = parent ? strrchr(parent, '/') : NULL;
  1099.       offset = filename ? filename - parent + 1 : 0;
  1100.       filename = XtMalloc(length + offset + 1 + FILE_SUFFIX_LEN);
  1101.       strncpy(filename, parent, offset);
  1102.       strcpy(&filename[offset], name);
  1103.       strcpy(&filename[offset + length], FILE_SUFFIX);
  1104.       stream = fopen(filename, "r");
  1105.       if(!stream)
  1106.         {
  1107.           filename[offset + length] = 0;
  1108.           stream = fopen(filename, "r");
  1109.         }
  1110.       if(!stream)
  1111.         /*{{{  try in app-defaults/xmris/<file>*/
  1112.         {
  1113.           char      *lib;
  1114.           
  1115.           lib = XtResolvePathname(display.display,
  1116.           "app-defaults/xmris", name, NULL, NULL, NULL, 0, NULL);
  1117.           if(!lib)
  1118.         lib = XtResolvePathname(display.display, "app-defaults/xmris",
  1119.             name, FILE_SUFFIX, NULL, NULL, 0, NULL);
  1120.           if(!lib && data.dir)
  1121.         lib = XtResolvePathname(display.display, data.dir, name,
  1122.             FILE_SUFFIX, "%T/%N:%T/%N%S:%T/gardens/%N:%T/gardens/%N%S",
  1123.             NULL, 0, NULL);
  1124.           if(lib)
  1125.         {
  1126.           XtFree(filename);
  1127.           filename = lib;
  1128.         }
  1129.           stream = fopen(filename, "r");
  1130.         }
  1131.         /*}}}*/
  1132.     }
  1133.       sptr->name = filename;
  1134.       if(!stream && filename)
  1135.     {
  1136.       perror(filename);
  1137.       error = ERROR_OPEN;
  1138.     }
  1139.     }
  1140.   else
  1141.     stream = 0;
  1142.   /*}}}*/
  1143.   do
  1144.     /*{{{  read a board*/
  1145.     {
  1146.       bptr = NULL;
  1147.       if(error)
  1148.     /* EMPTY */;
  1149.       else if(sptr->name)
  1150.     /*{{{  read board*/
  1151.     {
  1152.       /* state 0    new block
  1153.        * state 1    comment
  1154.        * state 2-4  numbers
  1155.        * state 5    open brace
  1156.        * state 6    close brace
  1157.        * state 7    close brace
  1158.        * state 10+  lines
  1159.        */
  1160.       unsigned  state;
  1161.       
  1162.       state = 0;
  1163.       sptr->start = sptr->line + 1;
  1164.       do
  1165.         {
  1166.           char      *ptr;
  1167.       
  1168.           /*{{{  read line*/
  1169.           {
  1170.         unsigned  temp;
  1171.           
  1172.         temp = read_line(stream, sptr);
  1173.         if(!error)
  1174.           sptr->error = sptr->line;
  1175.         if(temp)
  1176.           {
  1177.             error |= temp;
  1178.             break;
  1179.           }
  1180.           }
  1181.           /*}}}*/
  1182.           ptr = parse.text;
  1183.           if(!*ptr)
  1184.         {
  1185.           if(state)
  1186.             error |= ERROR_EOF;
  1187.           break;
  1188.         }
  1189.           while(*ptr == ' ' || *ptr == '\t')
  1190.         ptr++;
  1191.           if(*ptr == '\n')
  1192.         continue;
  1193.           /*{{{  new block*/
  1194.           if(state == 0)
  1195.         {
  1196.           if(ptr[0] == '/' && ptr[1] == '*')
  1197.             {
  1198.               ptr += 2;
  1199.               state = 1;
  1200.             }
  1201.           else if(!strncmp(ptr, "#include", 8))
  1202.             /*{{{  include*/
  1203.             {
  1204.               ptr += 8;
  1205.               while(*ptr == ' ' || *ptr == '\t')
  1206.             ptr++;
  1207.               if(*ptr == '\"')
  1208.             {
  1209.               char      *name;
  1210.               
  1211.               name = ++ptr;
  1212.               while(*ptr && *ptr != '\"')
  1213.                 ptr++;
  1214.               *ptr = 0;
  1215.               if(ptr == name)
  1216.                 name = NULL;
  1217.               if(parse.depth == INCLUDE_LIMIT)
  1218.                 {
  1219.                   error = ERROR_TOO_MANY;
  1220.                   break;
  1221.                 }
  1222.               sptr->seek = ftell(stream);
  1223.               fclose(stream);
  1224.               parse.depth++;
  1225.               read_boards(name, sptr->name);
  1226.               parse.depth--;
  1227.               stream = fopen(sptr->name, "r");
  1228.               if(!stream || fseek(stream, sptr->seek, SEEK_SET))
  1229.                 {
  1230.                   error = ERROR_OPEN;
  1231.                   perror(sptr->name);
  1232.                   break;
  1233.                 }
  1234.             }
  1235.               else
  1236.             {
  1237.               error = ERROR_SYNTAX;
  1238.               break;
  1239.             }
  1240.             }
  1241.             /*}}}*/
  1242.           else if(*ptr == '{')
  1243.             {
  1244.               ptr++;
  1245.               state = 2;
  1246.               bptr = malloc(sizeof(BOARD));
  1247.               if(!bptr)
  1248.             {
  1249.               error = ERROR_MALLOC;
  1250.               state = 7;
  1251.             }
  1252.             }
  1253.           else
  1254.             error = ERROR_SYNTAX;
  1255.         }
  1256.           /*}}}*/
  1257.           /*{{{  in comment*/
  1258.           if(state == 1)
  1259.         {
  1260.           while(*ptr && state)
  1261.             {
  1262.               while(*ptr && *ptr != '*')
  1263.             ptr++;
  1264.               if(*ptr)
  1265.             {
  1266.               if(ptr[1] == '/')
  1267.                 {
  1268.                   ptr += 2;
  1269.                   state = 0;
  1270.                   break;
  1271.                 }
  1272.               else
  1273.                 ptr++;
  1274.             }
  1275.             }
  1276.         }
  1277.           /*}}}*/
  1278.           /*{{{  reading board*/
  1279.           if(state >= 2)
  1280.         {
  1281.           while(state)
  1282.             {
  1283.               if(*ptr == ' ' || *ptr == '\t')
  1284.             ptr++;
  1285.               if(*ptr == '\n')
  1286.             break;
  1287.               switch(state)
  1288.               {
  1289.             /*{{{  case 2: case 3: case 4:*/
  1290.             case 2: case 3: case 4:
  1291.             {
  1292.               char      *eptr;
  1293.               unsigned  value;
  1294.               
  1295.               value = strtol(ptr, &eptr, 0);
  1296.               if(eptr == ptr)
  1297.                 {
  1298.                   error = ERROR_SYNTAX;
  1299.                   state = 7;
  1300.                 }
  1301.               else
  1302.                 {
  1303.                   switch(state)
  1304.                   {
  1305.                 case 2:
  1306.                   bptr->fill = value;
  1307.                   /* CASCADE */
  1308.                 case 3:
  1309.                   bptr->colors = value;
  1310.                   /* CASCADE */
  1311.                 case 4:
  1312.                   bptr->apples = value;
  1313.                   /* CASCADE */
  1314.                   }
  1315.                   ptr = eptr;
  1316.                   state++;
  1317.                 }
  1318.               break;
  1319.             }
  1320.             /*}}}*/
  1321.             /*{{{  case 5:*/
  1322.             case 5:
  1323.               if(*ptr == '{')
  1324.                 {
  1325.                   state = 10;
  1326.                   ptr++;
  1327.                 }
  1328.               else
  1329.                 {
  1330.                   state = 7;
  1331.                   error = ERROR_SYNTAX;
  1332.                 }
  1333.               break;
  1334.             /*}}}*/
  1335.             /*{{{  case 6:*/
  1336.             case 6:
  1337.               if(*ptr++ == '}')
  1338.                 state = 7;
  1339.               else
  1340.                 error = ERROR_SYNTAX;
  1341.               break;
  1342.             /*}}}*/
  1343.             /*{{{  case 7:*/
  1344.             case 7:
  1345.               if(*ptr == '}')
  1346.                 {
  1347.                   state = 0;
  1348.                   ptr++;
  1349.                 }
  1350.               else if(*ptr++ == '{')
  1351.                 state = 6;
  1352.               else
  1353.                 error = ERROR_SYNTAX;
  1354.               break;
  1355.             /*}}}*/
  1356.             /*{{{  default:*/
  1357.             default:
  1358.             {
  1359.               char      *eptr;
  1360.               
  1361.               assert(state >= 10 && state < 10 + CELLS_DOWN);
  1362.               eptr = strchr(ptr + 1, '\"');
  1363.               if(*ptr != '\"' || !eptr ||
  1364.                   eptr - ptr != CELLS_ACROSS + 1)
  1365.                 {
  1366.                   error = ERROR_SYNTAX;
  1367.                   state = 6;
  1368.                 }
  1369.               else
  1370.                 {
  1371.                   strncpy(bptr->map[state - 10], ptr + 1,
  1372.                   CELLS_ACROSS);
  1373.                   bptr->map[state - 10][CELLS_ACROSS] = 0;
  1374.                   state++;
  1375.                   ptr = eptr + 1;
  1376.                   if(state == 10 + CELLS_DOWN)
  1377.                 state = 6;
  1378.                 }
  1379.               break;
  1380.             }
  1381.             /*}}}*/
  1382.               }
  1383.               if(error && bptr)
  1384.             {
  1385.               free(bptr);
  1386.               bptr = NULL;
  1387.             }
  1388.               if(*ptr == ',')
  1389.             ptr++;
  1390.             }
  1391.         }
  1392.           /*}}}*/
  1393.         }
  1394.       while(state);
  1395.       if(!error && !*parse.text)
  1396.         break;
  1397.     }
  1398.     /*}}}*/
  1399.       else if(sptr->garden != sizeof(internal_boards) /
  1400.       sizeof(internal_boards[0]))
  1401.     bptr = &internal_boards[sptr->garden];
  1402.       else
  1403.     break;
  1404.       /*{{{  a new garden?*/
  1405.       if(bptr)
  1406.     {
  1407.       if(!(error & ERROR_FATAL_MASK))
  1408.         error |= check_board(bptr);
  1409.       if(board.boards == BOARD_LIMIT)
  1410.         error |= ERROR_TOO_MANY;
  1411.       if(!(error & ERROR_FATAL_MASK))
  1412.         board.list[board.boards++] = bptr;
  1413.       else
  1414.         {
  1415.           if(sptr->name)
  1416.         free(bptr);
  1417.           bptr = NULL;
  1418.         }
  1419.     }
  1420.       /*}}}*/
  1421.       /*{{{  error*/
  1422.       if(error)
  1423.     {
  1424.       unsigned  depth;
  1425.       int       ix;
  1426.       
  1427.       fprintf(stderr, "In file %s", sptr->name ? sptr->name :
  1428.           "<default>");
  1429.       for(depth = parse.depth; depth--;)
  1430.         fprintf(stderr, " included from %s:%d",
  1431.         parse.stack[depth].name, parse.stack[depth].line);
  1432.       fprintf(stderr, " line %d", sptr->error);
  1433.       if(sptr->start != sptr->line)
  1434.         fprintf(stderr, " garden %d (lines %d-%d)",
  1435.         sptr->garden + 1, sptr->start, sptr->line);
  1436.       fputc('\n', stderr);
  1437.       for(ix = 16; ix--;)
  1438.         if(error & 1 << ix)
  1439.           fprintf(stderr, "%s%s\n", text_error[ix],
  1440.           (1 << ix) & ERROR_FIX_MASK ? " (fixed)" : ""); 
  1441.       error &= ERROR_KEEP_MASK;
  1442.     }
  1443.       /*}}}*/
  1444.       if(bptr)
  1445.     sptr->garden++;
  1446.     }
  1447.     /*}}}*/
  1448.   while(!error);
  1449.   if(stream)
  1450.     fclose(stream);
  1451.   XtFree((char *)sptr->name);
  1452.   return;
  1453. }
  1454. /*}}}*/
  1455. /*{{{  unsigned read_line(stream)*/
  1456. static unsigned read_line
  1457. FUNCARG((stream, sptr),
  1458.     FILE    *stream
  1459. ARGSEP  INCLUDE *sptr
  1460. )
  1461. {
  1462.   size_t    length;
  1463.   char      *ptr;
  1464.   unsigned  error;
  1465.   char      *line;
  1466.   
  1467.   sptr->line++;
  1468.   error = 0;
  1469.   if(!parse.text)
  1470.     {
  1471.       parse.limit = 128;
  1472.       parse.text = malloc(128);
  1473.       if(!parse.text)
  1474.     return ERROR_MALLOC;
  1475.     }
  1476.   length = 0;
  1477.   ptr = parse.text;
  1478.   /*{{{  read line*/
  1479.   while((line = fgets(ptr, parse.limit - length, stream)))
  1480.     {
  1481.       ptr += strlen(ptr);
  1482.       length = ptr - parse.text;
  1483.       if(length && *(ptr - 1) == '\n')
  1484.     break;
  1485.       if(length + 1 < parse.limit)
  1486.     break;
  1487.       ptr = realloc(parse.text, parse.limit + 128);
  1488.       if(ptr)
  1489.     {
  1490.       parse.limit += 128;
  1491.       parse.text = ptr;
  1492.       ptr += length;
  1493.     }
  1494.       else
  1495.     {
  1496.       error = ERROR_MALLOC;
  1497.       break;
  1498.     }
  1499.     }
  1500.   /*}}}*/
  1501.   /*{{{  error?*/
  1502.   if(!line)
  1503.     {
  1504.       if(feof(stream))
  1505.     *parse.text = 0;
  1506.       else
  1507.     {
  1508.       perror(sptr->name);
  1509.       error = ERROR_READING;
  1510.     }
  1511.     }
  1512.   /*}}}*/
  1513.   return error;  
  1514. }
  1515. /*}}}*/
  1516. #endif /* !AMIGAOS */
  1517. /*{{{  void refresh_window()*/
  1518. extern VOIDFUNC refresh_window FUNCARGVOID
  1519. /*
  1520.  * refreshes the display window
  1521.  */
  1522. {
  1523.   if(global.state == MODE_ZOOM)
  1524.     {
  1525.       unsigned  x, y;
  1526.       
  1527.       x = global.count * ZOOM_X;
  1528.       y = global.count * ZOOM_Y;
  1529.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1530.       0, 0, WINDOW_WIDTH, BORDER_TOP + 1, 0, 0);
  1531.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1532.       0, BORDER_TOP + BOARD_HEIGHT - 1, WINDOW_WIDTH, BORDER_BOTTOM + 1,
  1533.       0, BORDER_TOP + BOARD_HEIGHT - 1);
  1534.       if(BORDER_LEFT > 0)
  1535.     XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1536.         0, BORDER_TOP, BORDER_LEFT + 1, BOARD_HEIGHT, 0, BORDER_TOP);
  1537.       if(BORDER_RIGHT > 0)
  1538.     XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1539.         BORDER_LEFT + BOARD_WIDTH - 1, BORDER_TOP, BORDER_RIGHT + 1,
  1540.         BOARD_HEIGHT, BORDER_LEFT + BOARD_WIDTH - 1, BORDER_TOP);
  1541.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1542.       CENTER_X - (int)x, CENTER_Y - (int)y, 2 * x, 2 * y,
  1543.       CENTER_X - (int)x, CENTER_Y - (int)y);
  1544.     }
  1545.   else
  1546.     XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1547.     0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  1548.   if(global.missed)
  1549.     XDrawLine(display.display, display.window, GCN(GC_LOAD),
  1550.     WINDOW_WIDTH - (int)global.missed,
  1551.     PIXELY(CELLS_DOWN, CELL_HEIGHT),
  1552.     WINDOW_WIDTH, PIXELY(CELLS_DOWN, CELL_HEIGHT));
  1553.   if(global.dilation != FRAME_SCALE)
  1554.     XDrawLine(display.display, display.window, GCN(GC_LOAD),
  1555.     0, PIXELY(CELLS_DOWN, CELL_HEIGHT),
  1556.     WINDOW_WIDTH - (int)((unsigned long)WINDOW_WIDTH * FRAME_SCALE /
  1557.         global.dilation), PIXELY(CELLS_DOWN, CELL_HEIGHT));
  1558.   return;
  1559. }
  1560. /*}}}*/
  1561. /*{{{  void set_back_sprite(ix)*/
  1562. extern VOIDFUNC set_back_sprite
  1563. FUNCARG((ix, cell_x, cell_y),
  1564.     unsigned  ix
  1565. ARGSEP  unsigned  cell_x
  1566. ARGSEP  unsigned  cell_y
  1567. )
  1568. /*
  1569.  * sets a den/prize sprite and draws it on the background
  1570.  */
  1571. {
  1572.   int       x;
  1573.   int       y;
  1574.   
  1575.   BOARDCELL(cell_x, cell_y)->sprite = ix;
  1576.   x = PIXELX(cell_x, 0);
  1577.   y = PIXELY(cell_y, 0);
  1578.   add_background(x, y, CELL_WIDTH, CELL_HEIGHT);
  1579.   XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  1580.       x, y, CELL_WIDTH, CELL_HEIGHT);
  1581.   back_sprite(ix, 0, x, y);
  1582.   return;
  1583. }
  1584. /*}}}*/
  1585. /*{{{  void show_updates()*/
  1586. extern VOIDFUNC show_updates FUNCARGVOID
  1587. /*
  1588.  * shows all the updates on the update list
  1589.  * and delete the dead apples and monsters.
  1590.  * remember to keep the monster lists intact.
  1591.  * the monsters a drawn in reverse order, so that the player
  1592.  * ends up on top of everybody.
  1593.  * We must be careful about the order of the update, so that there
  1594.  * isn't excessive flicker. That's why we have a copy window to do the
  1595.  * updates first, and then copy the relevant areas onto the display window
  1596.  */
  1597. {
  1598.   draw_ball(0);
  1599.   /*{{{  backgrounds to copy*/
  1600.   {
  1601.     unsigned  i;
  1602.     BACKGROUND *bptr;
  1603.     
  1604.     for(bptr = update.back.list, i = update.back.backs; i--; bptr++)
  1605.       XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  1606.       bptr->place.x, bptr->place.y, bptr->size.x, bptr->size.y,
  1607.       bptr->place.x, bptr->place.y);
  1608.   }
  1609.   /*}}}*/
  1610.   if(global.state != MODE_ZOOM)
  1611.     {
  1612.       /*{{{  do the monster backgrounds*/
  1613.       {
  1614.     int       i;
  1615.     MONSTER   *mptr;
  1616.     MONSTER   *nptr;
  1617.         
  1618.     for(mptr = nptr = monster.list, i = monster.monsters; i--; mptr++)
  1619.       {
  1620.         int   new;
  1621.         
  1622.         update.set = 0;
  1623.         if(mptr->type == 5)
  1624.           new = 0;
  1625.         else if(mptr->type == 6)
  1626.           new = SPRITE_DIAMOND + mptr->image;
  1627.         else if(mptr->type > 5)
  1628.           new = mptr->type;
  1629.         else if(mptr->chew)
  1630.           new = SPRITE_CHOMP + mptr->image;
  1631.         else if(mptr->face >= 16)
  1632.           new = SPRITE_SQUISHED - 16 + mptr->type * 2 + mptr->face;
  1633.         else
  1634.           new = SPRITE_MONSTERS + mptr->type * (6 * MONSTER_IMAGES) +
  1635.           mptr->face * MONSTER_IMAGES + mptr->image;
  1636.         if(!mptr->back && mptr->old_sprite && (new != mptr->old_sprite ||
  1637.         mptr->pixel.x != mptr->old_pixel.x ||
  1638.         mptr->pixel.y != mptr->old_pixel.y ||
  1639.         (mptr == &monster.list[0] &&
  1640.           !player.old_ball.state && player.ball.state)) &&
  1641.         mptr->on)
  1642.           {
  1643.         XCopyArea(display.display, display.back, display.copy,
  1644.             GCN(GC_COPY),
  1645.             mptr->old_pixel.x, mptr->old_pixel.y,
  1646.             CELL_WIDTH, CELL_HEIGHT,
  1647.             mptr->old_pixel.x, mptr->old_pixel.y);
  1648.         if(mptr->pixel.x != mptr->old_pixel.x ||
  1649.             mptr->pixel.y != mptr->old_pixel.y || !new)
  1650.           bounding_box(mptr->old_pixel.x, mptr->old_pixel.y,
  1651.               CELL_WIDTH, CELL_HEIGHT);
  1652.           }
  1653.         mptr->old_sprite = new;
  1654.         if(new)
  1655.           {
  1656.         mptr->old_pixel.x = mptr->pixel.x;
  1657.         mptr->old_pixel.y = mptr->pixel.y;
  1658.         mptr->on = INRANGE(mptr->pixel.x,
  1659.             1 - CELL_WIDTH, WINDOW_WIDTH) &&
  1660.             INRANGE(mptr->pixel.y, 1 - CELL_HEIGHT, WINDOW_HEIGHT);
  1661.         if(!mptr->back && mptr->on)
  1662.           bounding_box(mptr->old_pixel.x, mptr->old_pixel.y,
  1663.               CELL_WIDTH, CELL_HEIGHT);
  1664.         mptr->tptr = nptr;
  1665.         nptr++;
  1666.           }
  1667.         else
  1668.           mptr->tptr = NULL;
  1669.         mptr->back = 0;
  1670.         if(update.set)
  1671.           add_background(update.tl.x, update.tl.y,
  1672.           (unsigned)(update.br.x - update.tl.x),
  1673.           (unsigned)(update.br.y - update.tl.y));
  1674.       }
  1675.       }
  1676.       /*}}}*/
  1677.       /*{{{  do the apple backgrounds*/
  1678.       {
  1679.     int       i;
  1680.     APPLE     *aptr;
  1681.     APPLE     *dptr;
  1682.         
  1683.     for(aptr = dptr = apple.list, i = apple.apples; i--; aptr++)
  1684.       {
  1685.         int   new;
  1686.         
  1687.         update.set = 0;
  1688.         new = aptr->state;
  1689.         if(!aptr->back && (new != aptr->old_state ||
  1690.         aptr->pixel.x != aptr->old_pixel.x ||
  1691.         aptr->pixel.y != aptr->old_pixel.y))
  1692.           {
  1693.         APPLE_SIZE CONST *asp;
  1694.         int       x, y;
  1695.         unsigned  width, height;
  1696.         
  1697.         asp = &apple_sizes[aptr->old_state];
  1698.         x = aptr->old_pixel.x + asp->offset.x;
  1699.         y = aptr->old_pixel.y + asp->offset.y;
  1700.         width = asp->size.x;
  1701.         height = asp->size.y;
  1702.         XCopyArea(display.display, display.back, display.copy,
  1703.             GCN(GC_COPY), x, y, width, height, x, y);
  1704.         bounding_box(x, y, width, height);
  1705.           }
  1706.         if(new != 6)
  1707.           {
  1708.         APPLE_SIZE CONST *asp;
  1709.           
  1710.         aptr->old_pixel.x = aptr->pixel.x;
  1711.         aptr->old_pixel.y = aptr->pixel.y;
  1712.         aptr->old_state = new;
  1713.         asp = &apple_sizes[new];
  1714.         if(!aptr->back)
  1715.           bounding_box(aptr->old_pixel.x + asp->offset.x,
  1716.               aptr->old_pixel.y + asp->offset.y,
  1717.               asp->size.x, asp->size.y);
  1718.         if(aptr->list)
  1719.           {
  1720.             assert(aptr->list->tptr);
  1721.             aptr->list = aptr->list->tptr;
  1722.           }
  1723.         aptr->back = 0;
  1724.         if(aptr != dptr)
  1725.           memcpy(dptr, aptr, sizeof(APPLE));
  1726.         dptr++;
  1727.           }
  1728.         else
  1729.           apple.apples--;
  1730.         if(update.set)
  1731.           add_background(update.tl.x, update.tl.y,
  1732.           (unsigned)(update.br.x - update.tl.x),
  1733.           (unsigned)(update.br.y - update.tl.y));
  1734.       }
  1735.       }
  1736.       /*}}}*/
  1737.       /*{{{  do the apple sprites*/
  1738.       {
  1739.     int       i;
  1740.     APPLE     *aptr;
  1741.         
  1742.     for(aptr = apple.list, i = apple.apples; i--; aptr++)
  1743.       {
  1744.         SPRITE    *sptr;
  1745.         APPLE_SIZE CONST *asp;
  1746.         int       x, y;
  1747.         unsigned  width, height;
  1748.         
  1749.         asp = &apple_sizes[aptr->old_state];
  1750.         sptr = &sprites[(aptr->ghost && aptr->old_state < 3 ?
  1751.         SPRITE_GHOST : SPRITE_APPLE) + aptr->old_state];
  1752.         x = aptr->old_pixel.x + asp->offset.x;
  1753.         y = aptr->old_pixel.y + asp->offset.y;
  1754.         width = asp->size.x;
  1755.         height = asp->size.y;
  1756.         XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  1757.         0, 0, width, height, x, y);
  1758.         XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  1759.         0, 0, width, height, x, y);
  1760.       }
  1761.       }
  1762.       /*}}}*/
  1763.       /*{{{  do the monster sprites*/
  1764.       {
  1765.     int       i;
  1766.     MONSTER   *mptr;
  1767.         
  1768.     for(mptr = &monster.list[monster.monsters - 1], i = monster.monsters;
  1769.         i--; mptr--)
  1770.       if(mptr->old_sprite)
  1771.         {
  1772.           if(mptr->on)
  1773.         {
  1774.           SPRITE    *sptr;
  1775.           
  1776.           sptr = &sprites[mptr->old_sprite];
  1777.           XCopyArea(display.display, sptr->mask, display.copy,
  1778.               GCN(GC_MASK), 0, 0, CELL_WIDTH, CELL_HEIGHT,
  1779.               mptr->old_pixel.x, mptr->old_pixel.y);
  1780.           if(mptr->ghosting)
  1781.             /*{{{  ghosting*/
  1782.             {
  1783.               SPRITE    *dptr;
  1784.               COORD     offset;
  1785.               
  1786.               dptr = &sprites[SPRITE_GHOSTING];
  1787.               offset.x = mptr->ghosting & 0xF;
  1788.               offset.y = (mptr->ghosting >> 4) & 0xF;
  1789.               XCopyArea(display.display, sptr->image, dptr->image,
  1790.               GCN(GC_COPY), 0, 0, CELL_WIDTH, CELL_HEIGHT, 0, 0);
  1791.               XCopyArea(display.display, dptr->mask, dptr->image,
  1792.               GCN(GC_AND), offset.x, offset.y,
  1793.               CELL_WIDTH, CELL_HEIGHT, 0, 0);
  1794.               XCopyArea(display.display, dptr->image, display.copy,
  1795.               GCN(GC_OR), 0, 0, CELL_WIDTH, CELL_HEIGHT,
  1796.               mptr->old_pixel.x, mptr->old_pixel.y);
  1797.               XFillRectangle(display.display, dptr->image,
  1798.               GCN(GC_CLEAR), 0, 0, CELL_WIDTH, CELL_HEIGHT);
  1799.               XCopyArea(display.display, dptr->mask, dptr->image,
  1800.               GCN(GC_MASK), offset.x, offset.y,
  1801.               CELL_WIDTH, CELL_HEIGHT, 0, 0);
  1802.               XCopyArea(display.display, sptr->mask, dptr->image,
  1803.               GCN(GC_AND), 0, 0, CELL_WIDTH, CELL_HEIGHT, 0, 0);
  1804.               sptr = dptr;
  1805.               if(!mptr->cycle)
  1806.             /*{{{  drift*/
  1807.             {
  1808.               unsigned  temp;
  1809.               
  1810.               temp = chaotic();
  1811.               if(!(temp & 0x3) || offset.x == (mptr->ghosting &
  1812.                   0x200 ? GHOSTING_WIDTH - 1 - CELL_WIDTH : 0))
  1813.                 mptr->ghosting ^= 0x200;
  1814.               if(!(temp & 0xC) || offset.y == (mptr->ghosting &
  1815.                   0x400 ? GHOSTING_HEIGHT - 1 - CELL_HEIGHT : 0))
  1816.                 mptr->ghosting ^= 0x400;
  1817.               offset.x += mptr->ghosting & 0x200 ? 1 : -1;
  1818.               offset.y += mptr->ghosting & 0x400 ? 1 : -1;
  1819.               mptr->ghosting = (mptr->ghosting & 0x700) |
  1820.                   (offset.y << 4) | offset.x;
  1821.             }
  1822.             /*}}}*/
  1823.             }
  1824.             /*}}}*/
  1825.           XCopyArea(display.display, sptr->image, display.copy,
  1826.               GCN(GC_OR), 0, 0, CELL_WIDTH, CELL_HEIGHT,
  1827.               mptr->old_pixel.x, mptr->old_pixel.y);
  1828.         }
  1829.           if(mptr->squished)
  1830.         {
  1831.           if(mptr->list)
  1832.             {
  1833.               assert(mptr->list->tptr ||
  1834.             (mptr->type == 4 && mptr->list->type == 5));
  1835.               mptr->list = mptr->list->tptr;
  1836.             }
  1837.         }
  1838.           else
  1839.         mptr->list = NULL;
  1840.         }
  1841.       }
  1842.       /*}}}*/
  1843.     }
  1844.   memcpy(&player.old_ball, &player.ball, sizeof(BALL));
  1845.   draw_ball(1);
  1846.   /*{{{  scores to copy*/
  1847.   {
  1848.     unsigned  i;
  1849.     SCORE     *sptr;
  1850.     
  1851.     for(sptr = update.score.list, i = update.score.scores; i--; sptr++)
  1852.       {
  1853.     XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  1854.         0, 0, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  1855.         sptr->place.x, sptr->place.y);
  1856.     XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  1857.         0, 0, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  1858.         sptr->place.x, sptr->place.y);
  1859.       }
  1860.   }
  1861.   /*}}}*/
  1862.   /*{{{  areas to window*/
  1863.   {
  1864.     unsigned  i;
  1865.     BACKGROUND *bptr;
  1866.     
  1867.     for(bptr = update.back.list, i = update.back.backs; i--; bptr++)
  1868.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1869.       bptr->place.x, bptr->place.y, bptr->size.x, bptr->size.y,
  1870.       bptr->place.x, bptr->place.y);
  1871.   }
  1872.   /*}}}*/
  1873.   /*{{{  scores to window*/
  1874.   {
  1875.     unsigned  i;
  1876.     SCORE     *sptr;
  1877.     
  1878.     for(sptr = update.score.list, i = update.score.scores; i--; sptr++)
  1879.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  1880.       sptr->place.x, sptr->place.y, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  1881.       sptr->place.x, sptr->place.y);
  1882.   }
  1883.   /*}}}*/
  1884.   /*{{{  delete monsters*/
  1885.   {
  1886.     MONSTER   *mptr;
  1887.     unsigned  count;
  1888.     
  1889.     for(mptr = monster.list, count = monster.monsters; count--; mptr++)
  1890.       if(!mptr->old_sprite)
  1891.     monster.monsters--;
  1892.       else if(mptr != mptr->tptr)
  1893.     memcpy(mptr->tptr, mptr, sizeof(MONSTER));
  1894.   }
  1895.   /*}}}*/
  1896.   update.back.backs = 0;
  1897.   XSync(display.display, False);
  1898.   return;
  1899. }
  1900. /*}}}*/
  1901.  
  1902. /************************************************************************/
  1903. /*                                    */
  1904. /* Munch the "partial" cells.                        */
  1905. /* This is pretty hackish, but it seems to work.            */
  1906. /*                                    */
  1907. /************************************************************************/
  1908.  
  1909. static INLINE void MunchStuff(void)
  1910.  
  1911. {
  1912.   MONSTER Monster;
  1913.   unsigned apples;
  1914.  
  1915.   Monster.type=4;
  1916.   Monster.pause=FALSE;
  1917.   Monster.stop=FALSE;
  1918.   Monster.panic=FALSE;
  1919.   Monster.shot=FALSE;
  1920.   Monster.fast=FALSE;
  1921.   Monster.list=NULL;
  1922.   Monster.tptr=NULL;
  1923.   Monster.face=0;
  1924.   Monster.push=FALSE;
  1925.   Monster.gomunch=FALSE;
  1926.   Monster.ghosting=FALSE;
  1927.   Monster.cont=FALSE;
  1928.   Monster.chew=FALSE;
  1929.   Monster.count=0;
  1930.   Monster.cycle=FALSE;
  1931.   Monster.image=SPRITE_PLAYER;
  1932.   Monster.pushing=FALSE;
  1933.   Monster.squished=FALSE;
  1934.   Monster.old_pixel.x=0;
  1935.   Monster.old_pixel.y=0;
  1936.   Monster.old_sprite=SPRITE_PLAYER;
  1937.   Monster.back=0;
  1938.   Monster.on=TRUE;
  1939.   apples=apple.apples;
  1940.   apple.apples=0;
  1941.   for (Monster.cell.x=0; Monster.cell.x<CELLS_ACROSS; Monster.cell.x++)
  1942.     {
  1943.       for (Monster.cell.y=0; Monster.cell.y<CELLS_DOWN; Monster.cell.y++)
  1944.     {
  1945.       CELL *cptr;
  1946.       int depths[4];
  1947.  
  1948.       cptr=BOARDCELL(Monster.cell.x,Monster.cell.y);
  1949.       if (cptr->visit)
  1950.         {
  1951.           memcpy(depths,cptr->depths,sizeof(cptr->depths));
  1952.  
  1953.           cptr->depths[0]=0;
  1954.           cptr->depths[1]=0;
  1955.           cptr->depths[2]=0;
  1956.           cptr->depths[3]=0;
  1957.  
  1958.           for (Monster.dir=0; Monster.dir<4; Monster.dir++)
  1959.         {
  1960.           Monster.offset.x=0;
  1961.           Monster.offset.y=0;
  1962.           Monster.pixel.x=PIXELX(Monster.cell.x,Monster.offset.x);
  1963.           Monster.pixel.y=PIXELY(Monster.cell.y,Monster.offset.y);
  1964.           if (Monster.dir&1)
  1965.             {
  1966.               while (cptr->depths[Monster.dir]<depths[Monster.dir])
  1967.             {
  1968.               update.back.backs=0;
  1969.               move_muncher(&Monster);
  1970.             }
  1971.             }
  1972.           else
  1973.             {
  1974.               while (cptr->depths[Monster.dir]>depths[Monster.dir])
  1975.             {
  1976.               update.back.backs=0;
  1977.               move_muncher(&Monster);
  1978.             }
  1979.             }
  1980.         }
  1981.  
  1982.           memcpy(cptr->depths,depths,sizeof(cptr->depths));
  1983.         }
  1984.     }
  1985.     }
  1986.   apple.apples=apples;
  1987. }
  1988.  
  1989. /************************************************************************/
  1990. /*                                    */
  1991. /* Recreate the offscreen bitmaps.                    */
  1992. /* This is called after the window is opened and the sprites have been    */
  1993. /* created.                                */
  1994. /*                                    */
  1995. /************************************************************************/
  1996.  
  1997. void RedrawGame(void)
  1998.  
  1999. {
  2000.   int cell_y;
  2001.  
  2002.   create_xtra_monster(extra.select);
  2003.   draw_blank_background(&board.list[(global.screen-1)%board.boards], (global.screen-1)/board.boards);
  2004.   MunchStuff();
  2005.   new_board_draw();
  2006.   for (cell_y=0; cell_y!=CELLS_DOWN; cell_y++)
  2007.     {
  2008.       int cell_x;
  2009.  
  2010.       for (cell_x=0; cell_x!=CELLS_ACROSS; cell_x++)
  2011.     {
  2012.       if(BOARDCELL(cell_x, cell_y)->den)
  2013.         {
  2014.           set_back_sprite(global.state ? global.state != 1 ?
  2015.                   0 : (global.screen - 1) % SPRITE_PRIZES +
  2016.                   SPRITE_PRIZE_BASE : SPRITE_DEN, cell_x, cell_y);
  2017.         }
  2018.     }
  2019.     }
  2020.   refresh_window();
  2021. }
  2022.